package org.vaadin.golfscoretracker.ui.components;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.vaadin.appfoundation.i18n.Lang;
import org.vaadin.golfscoretracker.data.Course;
import org.vaadin.golfscoretracker.data.Hole;

import com.vaadin.data.Validator.InvalidValueException;
import com.vaadin.data.util.BeanItem;
import com.vaadin.ui.Button;
import com.vaadin.ui.CustomField;
import com.vaadin.ui.Form;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;

public class HolesEditorField extends CustomField implements ClickListener {

    private static final long serialVersionUID = -2078320495152611248L;

    private final VerticalLayout mainLayout = new VerticalLayout();

    private final Button addHoleBtn = new Button(Lang.getMessage("add"),
            (ClickListener) this);

    private final Course course;

    private final Map<Hole, Form> forms = new HashMap<Hole, Form>();

    public HolesEditorField(Course course) {
        this.course = course;
        setCompositionRoot(mainLayout);
        mainLayout.addComponent(addHoleBtn);
    }

    @Override
    public Class<?> getType() {
        return List.class;
    }

    @Override
    public void buttonClick(ClickEvent event) {
        Hole hole = new Hole();
        hole.setCourse(course);
        addHole(hole, true);
    }

    @SuppressWarnings("unchecked")
    private void addHole(Hole hole, boolean addToList) {
        BeanItem<Hole> item = new BeanItem<Hole>(hole);
        Form form = new Form();
        form.setFormFieldFactory(new HoleFieldFactory());
        form.setLayout(new HorizontalLayout());
        form.setItemDataSource(item);
        form.setVisibleItemProperties(new Object[] { "length", "par" });
        mainLayout.addComponent(form);

        forms.put(hole, form);

        if (addToList) {
            List<Hole> holes = (List<Hole>) getValue();
            if (holes == null) {
                holes = new ArrayList<Hole>();
                setInternalValue(holes);
            }
            holes.add(hole);
        }
    }

    @Override
    public void commit() throws SourceException, InvalidValueException {
        super.commit();
        for (Form form : forms.values()) {
            form.commit();
        }
    }

    @Override
    public void validate() throws InvalidValueException {
        super.validate();
        for (Form form : forms.values()) {
            form.validate();
        }
    }

    @Override
    public boolean isValid() {
        if (!super.isValid()) {
            return false;
        }
        for (Form form : forms.values()) {
            if (!form.isValid()) {
                return false;
            }
        }

        return true;
    }

    @Override
    public void discard() throws SourceException {
        super.discard();
        for (Form form : forms.values()) {
            form.discard();
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void setInternalValue(Object newValue) {
        super.setInternalValue(newValue);
        if (newValue == null) {
            return;
        }

        List<Hole> holes = (List<Hole>) newValue;
        for (Hole hole : holes) {
            addHole(hole, false);
        }
    }

}
